package com.zzyq.pc.web.report.serviceImpl;

import java.awt.Dimension;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zzyq.pc.utils.DateUtils;
import com.zzyq.pc.utils.JsonUtils;
import com.zzyq.pc.utils.ReportUtils;
import com.zzyq.pc.web.report.base.TableField;
import com.zzyq.pc.web.report.response.ModuleData;
import com.zzyq.pc.web.report.service.IDocExportor;

/**
 * Word数据处理<br>
 * 使用Apache_POI_3.8-XWPF生成简易Word文档
 * 
 * @author shengchen
 *
 */
public class WordDocExportor implements IDocExportor {
	private OutputStream out;

	/**
	 * 获取文档对象
	 */
	protected XWPFDocument getDoc() {
		return doc;
	}

	/**
	 * WordDoc文档XWPF对象
	 */
	private XWPFDocument doc = new XWPFDocument();

	/**
	 * 根据位置创建XWPF对象
	 */
	private XWPFParagraph createXWPFParagraph(Align align) {
		XWPFParagraph xwpf = getDoc().createParagraph();
		xwpf.setAlignment(getAlign(align));
		return xwpf;
	}

	private ParagraphAlignment getAlign(Align align) {
		switch (align) {
		case Center:
			return ParagraphAlignment.CENTER;
		case Left:
			return ParagraphAlignment.LEFT;
		case Right:
			return ParagraphAlignment.RIGHT;
		default:
			return ParagraphAlignment.CENTER;
		}
	}

	/**
	 * @Description: 得到单元格第一个Paragraph
	 */
	private XWPFParagraph getCellFirstParagraph(XWPFTableCell cell) {
		XWPFParagraph p;
		if (cell.getParagraphs() != null && cell.getParagraphs().size() > 0) {
			p = cell.getParagraphs().get(0);
		} else {
			p = cell.addParagraph();
		}
		return p;
	}

	private void setCellContent(XWPFTable table, int row, int col, DocFont font, String text) {
		XWPFTableCell cell = table.getRow(row).getCell(col);
		XWPFParagraph paragraph = getCellFirstParagraph(cell);
		paragraph.setAlignment(getAlign(Align.Center));
		List<XWPFRun> cellRunList = paragraph.getRuns();
		XWPFRun run = null;
		if (cellRunList == null || cellRunList.size() == 0) {
			run = paragraph.createRun();
		} else {
			for (int o = cellRunList.size() - 1; o >= 1; o--) {
				paragraph.removeRun(o);
			}
			// 设置标题信息
			run = cellRunList.get(0);
		}
		run.setBold(font.getBold());
		run.setFontSize(font.getSize());
		run.setFontFamily(font.getFont());
		run.setText(text);
	}

	/**
	 * 根据数据解析后写入到word文档
	 * 
	 * @param infos
	 *            一些标题注释信息等
	 * @param moduleDatas
	 *            排序的模块数据，包括标题等信息
	 * @param svg
	 *            有图表的svg字符串，根据模块信息里的标题取出，并生成图片插入word
	 * @param out
	 *            word的输出流对象
	 * @return
	 */
	@Override
	public IDocExportor createDoc(Map<String, String> infos, List<ModuleData> moduleDatas, Map<String, String> svg,
			OutputStream out) {
		this.out = out;
		try {
			writeLine();
			// 写入报告的标题信息
			writeText(infos.get(GAROUP_NAME), DocFont.TitleDoc, Align.Center);
			// writeText(infos.get(RPT_NAME), DocFont.TitleDoc, Align.Center);
			writeLine();
			// 遍历获取到的模块数据信息，依次写入Word
			for (ModuleData moduleData : moduleDatas) {
				// 判断模块是否显示
				// if (!moduleData.getShow()) {
				// continue;
				// }
				// 写入模块标题
				String moduleTitle = moduleData.getTitle();
				writeText(moduleTitle, DocFont.TitleModule, Align.Left);
				// 写入模块的文字信息
				String moduleText = moduleData.getText();
				if (StringUtils.isNoneBlank(moduleText)) {
					writeText(moduleText, DocFont.Content, Align.Left);
				}
				// 开始插入图片
				String svgStr = svg.get(moduleData.getId() + "");
				// 根据展示类型判断是否加载并写入图片>2表示表格以上
				if (moduleData.getTypeId() > 2 && StringUtils.isNoneBlank(svgStr)) {
					// byte[] bytes = ReportUtils.convertToPngByte(svgStr);
					byte[] bytes = Base64.decodeBase64(svgStr);
					writeImage(bytes, null, null);
				} else if (moduleData.getTypeId() == 2 && !moduleData.getDataList().isEmpty()
						&& !moduleData.getTableFields().isEmpty()) {// 绘制表格
					// 将数据信息转换为json数据
					String dataJson = JsonUtils.toString(moduleData.getDataList(), "yyyy-MM-dd HH:mm:ss");
					// 计算行数
					int rowSize = 0;
					if (moduleData.isPullByList()) {
						if (null != moduleData.getDataList().get(0).datas) {
						rowSize = moduleData.getDataList().size() * moduleData.getDataList().get(0).getDatas().size();
						} else {
							rowSize = moduleData.getDataList().size()
									* moduleData.getDataList().get(0).getDatas2().size();
						}
					} else {
						if (null != moduleData.getDataList().get(0).datas) {
							rowSize = moduleData.getDataList().get(0).getDatas().size();
						} else {
							rowSize = moduleData.getDataList().get(0).getDatas2().size();
						}
					}
					writeTable(moduleData.getTableFields(), dataJson, moduleData.isPullByList(), rowSize);
				} else if (moduleData.getTypeId() == 1 && moduleData.getDataList() != null
						&& moduleData.getDataList().size() > 0) {// 填充文字列表
					String dataJson = JsonUtils.toString(moduleData.getDataList(), "yyyy-MM-dd HH:mm:ss");
					writeTextList(moduleData.getTableFields(), dataJson);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return this;
	}

	@Override
	public void writeToStream() throws Exception {
		getDoc().write(out);
	}

	@Override
	public void writeTable(List<TableField> fields, String dataJson, boolean isPullByList, int rowSize)
			throws Exception {
		// 获取列数量
		int colSize = fields.size();
		// 根据计算的行列来新建一个保存表格元素的二维数组（这里的行数包含标题项）
		rowSize += 1;
		// 从json数据中解析出树
		JsonNode root = new ObjectMapper().readTree(dataJson);
		// 表格的总宽度
		int totalWidth = 9000;
		// 这里计算每一列的宽度占比
		int[] widths = new int[colSize];
		for (int i = 0; i < colSize; i++) {
			widths[i] = (int) (totalWidth * fields.get(i).getWidthPercent());
		}
		// 开始生成表格
		XWPFTable table = getDoc().createTable(rowSize, colSize);
		// 设置表格的样式、宽度等，初始化操作
		CTTbl ttbl = table.getCTTbl();
		CTTblPr tablePr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr();
		CTTblWidth width = tablePr.isSetTblW() ? tablePr.getTblW() : tablePr.addNewTblW();
		width.setW(BigInteger.valueOf(totalWidth));
		CTTblGrid tblGrid = ttbl.getTblGrid() != null ? ttbl.getTblGrid() : ttbl.addNewTblGrid();
		for (int j = 0, len = widths.length; j < len; j++) {
			CTTblGridCol gridCol = tblGrid.addNewGridCol();
			gridCol.setW(new BigInteger(String.valueOf(widths[j])));
		}
		// BaseColor lightGrey = new BaseColor(0xCC, 0xCC, 0xCC);
		// BaseColor firstColor = new BaseColor(77, 83, 97);
		// 下面的for生成标题栏
		for (int i = 0; i < colSize; i++) {
			setCellContent(table, 0, i, DocFont.TitleModule, fields.get(i).getTitle());
		}
		// 行数计数器.为了精准添加数据到表格的坐标而计算的行数值
		int row = 0;
		// 开始解析并填充表格数据
		Iterator<JsonNode> moduleDataIterator = root.elements();
		while (moduleDataIterator.hasNext()) {
			// 如果不是按照普通的表格排列，则表格的行数不是数据类型列表数*值列表数，而只是数据列表数
			// 故重新设置行数为0
			if (!isPullByList) {
				row = 0;
			}
			// 拿出第一层数据列表
			JsonNode typeData = moduleDataIterator.next();
			// 获取这个数据的标题
			String dataName = typeData.findValue("title").asText();
			// 获取到这一行的数据
			JsonNode dataList = typeData.path("datas");
			// 获取到这一行的数据
			JsonNode dataList2 = typeData.path("datas2");
			// 在类型数据中获取真正值数据的迭代。
			Iterator<JsonNode> dataIterator = dataList.elements();
			if (!dataIterator.hasNext()) {
				dataIterator = dataList2.elements();
			}
			while (dataIterator.hasNext()) {
				// 每循环一个数据对象，行数+1,这里包括了标题这一行，所以要提前+1
				row++;
				// 这个data代表一个数据信息，即最终取到的包含值的对象
				JsonNode data = dataIterator.next();
				// 再次遍历列标题信息数组，进行field匹配，匹配到的则取出值

				for (int i = 0; i < colSize; i++) {
					// 获取这一列定义的的标题信息
					TableField field = fields.get(i);
					// 拼接显示的文本，定义一个文本对象
					StringBuilder value = new StringBuilder();
					String dataListField = field.getDataListField();
					String valueField = field.getValueField();
					// 格式化文本的format
					String textFormat = field.getTextFormat();
					// 格式化日期的format
					String dateFormat = field.getTimeFormat();
					// 超链接的field
					// String urlField = field.getUrlField();

					// 若匹配到此列跟此行数据来源一致
					if (StringUtils.isNotBlank(dataName) && StringUtils.isNotBlank(dataListField)
							&& dataListField.equals(dataName)) {
						String str = "";
						// 首先判断是否需要自增的序号
						if (field.isIncr()) {
							value.append(row + "");
						}
						// 取出文本值
						if (StringUtils.isNotBlank(valueField)) {
							try {
								str = data.findValue(valueField).asText();
							} catch (Exception e) {
								e.printStackTrace();
							}
							if (StringUtils.isNotBlank(textFormat)) {
								// 判断是否需要格式化填充文本
								// str = String.format(textFormat, str);
								str = str + textFormat;
							} else if (StringUtils.isNotBlank(dateFormat)) {
								// 判断是否需要格式化文本日期
								try {
									str = DateUtils.printDate(DateUtils.paraseStringToDate(str, "yyyy-MM-dd HH:mm:ss"),
											field.getTimeFormat());
								} catch (Exception e) {
								}
							}
							// 最后拼接文本则为最后显示的
							value.append(str);
						}
						// 这里字体需要新建对象，否则影响其他的字体

						// 创建字体和表格元素对象
						setCellContent(table, row, i, DocFont.Content, value.toString());
					} else {
						// 没有找到匹配的field字段
						continue;
					}
				}
			}
		}
	}

	@Override
	public void writeTextList(List<TableField> fields, String dataJson) throws Exception {
		// 获取列数量
		int colSize = fields.size();
		// 从json数据中解析出树
		JsonNode root = new ObjectMapper().readTree(dataJson);
		int row = 0;
		// 开始解析并填充表格数据
		Iterator<JsonNode> moduleDataIterator = root.elements();
		while (moduleDataIterator.hasNext()) {
			// 拿出第一层数据列表
			JsonNode typeData = moduleDataIterator.next();
			// 获取这个数据的标题
			String dataName = typeData.findValue("title").asText();
			// 获取到这一行的数据
			JsonNode dataList = typeData.path("datas");
			// 在类型数据中获取真正值数据的迭代。
			Iterator<JsonNode> dataIterator = dataList.elements();
			while (dataIterator.hasNext()) {
				// 这个data代表一个数据信息，即最终取到的包含值的对象
				JsonNode data = dataIterator.next();
				// 再次遍历列标题信息数组，进行field匹配，匹配到的则取出值
				for (int i = 0; i < colSize; i++) {
					// 获取这一列定义的的标题信息
					TableField field = fields.get(i);
					// 拼接显示的文本，定义一个文本对象
					StringBuilder value = new StringBuilder();
					String dataListField = field.getDataListField();
					String valueField = field.getValueField();
					// 格式化文本的format
					String textFormat = field.getTextFormat();
					// 格式化日期的format
					String dateFormat = field.getTimeFormat();

					// 若匹配到此列跟此行数据来源一致
					if (StringUtils.isNotBlank(dataName) && StringUtils.isNotBlank(dataListField)
							&& dataListField.equals(dataName)) {
						String str = "";
						// 首先判断是否需要自增的序号
						if (field.isIncr()) {
							value.append((row + 1) + "");
						}
						// 取出文本值
						if (StringUtils.isNotBlank(valueField)) {
							str = data.findValue(field.getValueField()).asText();
							if (StringUtils.isNotBlank(textFormat)) {
								// 判断是否需要格式化填充文本
								str = String.format(textFormat, str);
							} else if (StringUtils.isNotBlank(dateFormat)) {
								// 判断是否需要格式化文本日期
								try {
									str = DateUtils.printDate(DateUtils.paraseStringToDate(str, "yyyy-MM-dd HH:mm:ss"),
											field.getTimeFormat());
								} catch (Exception e) {
								}
							}
							// 最后拼接文本则为最后显示的
							value.append(str);
						}
						// 创建字体和表格元素对象
						// 这里字体需要新建对象，否则影响其他的字体
						XWPFParagraph xwpf = createXWPFParagraph(Align.Left);
						xwpf.setIndentationFirstLine(400);
						XWPFRun xwpfRun = xwpf.createRun();
						xwpfRun.setText(value.toString());
						xwpfRun.setBold(i == 0);
						xwpfRun.setFontFamily(DocFont.Content.getFont());
						xwpfRun.setFontSize(DocFont.Content.getSize());
					} else {
						// 没有找到匹配的field字段
						continue;
					}
				}
				// 每循环一个数据对象，行数+1
				writeLine();
				row++;
			}
		}
	}

	@Override
	public void writeImage(byte[] bytes, Dimension size, Align align) throws Exception {
		if (bytes.length == 0) {
			return;
		}
		if (size == null) {
			size = ReportUtils.getImgDimension(new ByteArrayInputStream(bytes));
		}
		if (size == null) {
			return;
		}
		if (align == null) {
			align = Align.Center;
		}
		XWPFParagraph xwpf = createXWPFParagraph(align);
		xwpf.createRun().addPicture(new ByteArrayInputStream(bytes), XWPFDocument.PICTURE_TYPE_PNG, "",
				Units.toEMU(size.getWidth()), Units.toEMU(size.getHeight()));
	}

	@Override
	public void writeText(String text, DocFont font, Align align) throws Exception {
		if (StringUtils.isBlank(text)) {
			return;
		}
		font = font == null ? DocFont.TitleModule : font;
		align = align == null ? Align.Left : align;
		XWPFParagraph xwpf = createXWPFParagraph(align);
		XWPFRun xwpfRun = xwpf.createRun();
		xwpfRun.setText(text);
		xwpfRun.setBold(font.getBold());
		xwpfRun.setFontFamily(font.getFont());
		xwpfRun.setFontSize(font.getSize());
	}

	@Override
	public void writeLine() throws Exception {
		XWPFParagraph xwpf = createXWPFParagraph(Align.Center);
		XWPFRun xwpfRun = xwpf.createRun();
		xwpfRun.setText("");
		xwpfRun.setBold(true);
		xwpfRun.setFontFamily("");
		xwpfRun.setFontSize(0);
	}

}
